//package com.xzzz.irda.guardcat.server.repos.elasticsearch;
//
//import cn.hutool.core.date.DateTime;
//import cn.hutool.core.date.DateUtil;
//import cn.hutool.core.map.MapUtil;
//import cn.hutool.core.net.URLDecoder;
//import cn.hutool.core.util.ObjUtil;
//import cn.hutool.core.util.StrUtil;
//import cn.hutool.json.JSONUtil;
//import com.xzzz.common.base.exception.XzException400;
//import com.xzzz.common.base.exception.XzException500;
//import com.xzzz.common.base.pojo.R;
//import com.xzzz.expand.es.core.EsCurdManager;
//import com.xzzz.irda.guardcat.server.log.pojo.*;
//import com.xzzz.irda.guardcat.server.repos.elasticsearch.pojo.EsAnalyzerReq;
//import com.xzzz.irda.guardcat.server.repos.elasticsearch.pojo.EsPageRes;
//import com.xzzz.irda.guardcat.server.repos.elasticsearch.pojo.EsPageVO;
//import lombok.Data;
//import lombok.extern.slf4j.Slf4j;
//import org.elasticsearch.action.search.SearchResponse;
//import org.elasticsearch.client.indices.AnalyzeResponse;
//import org.elasticsearch.common.unit.TimeValue;
//import org.elasticsearch.index.query.*;
//import org.elasticsearch.search.SearchHit;
//import org.elasticsearch.search.SearchHits;
//import org.elasticsearch.search.aggregations.AggregationBuilder;
//import org.elasticsearch.search.aggregations.AggregationBuilders;
//import org.elasticsearch.search.aggregations.Aggregations;
//import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
//import org.elasticsearch.search.aggregations.bucket.histogram.ExtendedBounds;
//import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
//import org.elasticsearch.search.aggregations.bucket.histogram.ParsedDateHistogram;
//import org.elasticsearch.search.builder.SearchSourceBuilder;
//import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
//import org.elasticsearch.search.sort.SortOrder;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.web.bind.annotation.*;
//
//import java.nio.charset.StandardCharsets;
//import java.util.ArrayList;
//import java.util.Date;
//import java.util.List;
//
///**
// * 【Server】日志[ES]
// *
// * @apiNote 主要是ES日志收集的拓展接口，提供日志查询，聚合功能
// */
//@Slf4j
//@RestController
//@RequestMapping("/log")
//public class LogControllerInEs {
//
//    private static final List<String> levels = new ArrayList<String>() {{
//        this.add("DEBUG");
//        this.add("INFO");
//        this.add("WARN");
//        this.add("ERROR");
//    }};
//
//    @Autowired
//    private EsCurdManager esCurdManager;
//
//    /**
//     * 分词功能
//     *
//     * @param analyzerVO 分词对象
//     * @return 分词结果集合
//     */
//    @PostMapping("/analyze")
//    public R<?> analyze(@RequestBody EsAnalyzerReq analyzerVO) {
//        AnalyzeResponse response = esCurdManager.analyze(analyzerVO.getAnalyzer(), analyzerVO.getText());
//        if (analyzerVO.getSimple() != null && analyzerVO.getSimple()) {
//            List<String> terms = new ArrayList<>();
//            for (AnalyzeResponse.AnalyzeToken token : response.getTokens()) {
//                terms.add(token.getTerm());
//            }
//            return R.ok(terms);
//        }
//        return R.ok(response.getTokens());
//    }
//
//    /**
//     * 搜索日志分页
//     *
//     * @param pageNum           当前页
//     * @param pageSize          每页行数
//     * @param indexName         索引名称, 通常是index_backend_log
//     * @param appName           应用名称
//     * @param beginDate         开始时间
//     * @param endDate           结束时间
//     * @param logLevel          日志级别
//     * @param traceId           追踪ID
//     * @param message           匹配的日志内容
//     * @param notMessage        排除的日志内容
//     * @param sortHitScoreDesc  按照命中分数排序, 与 sortTimestampDesc 互斥
//     * @param sortTimestampDesc 按照时间戳排序, 与 sortHitScoreDesc 互斥
//     * @param matchOperator     message 字段匹配时使用 Operator.AND
//     * @param highlight         高亮命中内容
//     * @param debug             开启搜索DEBUG
//     */
//    @GetMapping("/log/page")
//    public R<EsPageRes<?>> page(
//            @RequestParam Integer pageNum,
//            @RequestParam Integer pageSize,
//            @RequestParam String indexName,
//            @RequestParam(required = false) String appName,
//            @RequestParam(required = false) String beginDate,
//            @RequestParam(required = false) String endDate,
//            @RequestParam(required = false) String logLevel,
//            @RequestParam(required = false) String traceId,
//            @RequestParam(required = false) String message,
//            @RequestParam(required = false) String notMessage,
//            @RequestParam(required = false) boolean sortHitScoreDesc,
//            @RequestParam(required = false) boolean sortTimestampDesc,
//            @RequestParam(required = false) boolean matchOperator,
//            @RequestParam(required = false) boolean highlight,
//            @RequestParam(required = false) boolean debug
//    ) {
//        traceId = URLDecoder.decode(traceId, StandardCharsets.UTF_8);
//        message = URLDecoder.decode(message, StandardCharsets.UTF_8);
//        notMessage = URLDecoder.decode(notMessage, StandardCharsets.UTF_8);
//
//        DateSection dateSection = getDateSection();
//        SearchSourceBuilder searchSource = new SearchSourceBuilder()
//                .timeout(TimeValue.timeValueSeconds(5)).from((pageNum - 1) * pageSize).size(pageSize)
//                .fetchSource(new String[]{"datetime", "level", "thread", "traceId", "class", "message", "ip", "hostName", "appName"}, null);
//        BoolQueryBuilder bool = new BoolQueryBuilder();
//        searchSource.query(bool);
//
//        // 开始时间
//        if (StrUtil.isBlank(beginDate)) {
//            beginDate = dateSection.getBeginDT();
//        } else {
//            try {
//                DateUtil.parseDateTime(beginDate);
//            } catch (Exception e) {
//                throw new XzException500("日志开始时间格式错误， 请遵照格式: yyyy-MM-dd HH:mm:ss");
//            }
//        }
//
//        // 结束时间
//        if (StrUtil.isBlank(endDate)) {
//            endDate = dateSection.getEndDT();
//        } else {
//            try {
//                DateUtil.parseDateTime(endDate);
//            } catch (Exception e) {
//                throw new XzException500("日志结束时间格式错误， 请遵照格式: yyyy-MM-dd HH:mm:ss");
//            }
//        }
//
//        // 时间区间
//        RangeQueryBuilder dateRange = QueryBuilders.rangeQuery("datetime").format("yyyy-MM-dd HH:mm:ss").gte(beginDate).lte(endDate);
//        if (sortHitScoreDesc) bool.must(dateRange);
//        else if (sortTimestampDesc) bool.filter(dateRange);
//        // .timeZone("+08:00");
//
//        // 日志级别
//        if (StrUtil.isNotBlank(logLevel)) {
//            MatchQueryBuilder matchLevel = QueryBuilders.matchQuery("level", logLevel);
//            if (sortHitScoreDesc) bool.must(matchLevel);
//            else if (sortTimestampDesc) bool.filter(matchLevel);
//        }
//
//        // 应用名称
//        if (StrUtil.isNotBlank(appName)) {
//            MatchQueryBuilder matchAppName = QueryBuilders.matchQuery("appName", appName);
//            if (sortHitScoreDesc) bool.must(matchAppName);
//            else if (sortTimestampDesc) bool.filter(matchAppName);
//        }
//
//        // traceId
//        if (StrUtil.isNotBlank(traceId)) {
//            MatchQueryBuilder matchTraceId = QueryBuilders.matchQuery("traceId", traceId);
//            if (sortHitScoreDesc) bool.must(matchTraceId);
//            else if (sortTimestampDesc) bool.filter(matchTraceId);
//        }
//
//        // 包含的 message
//        if (StrUtil.isNotBlank(message)) {
//            if (highlight) {
//                searchSource.highlighter(new HighlightBuilder()
//                        .highlighterType("plain")
//                        .field("message")
//                        .fragmentSize(2000)
//                        .preTags("<span style='color:#000000;background-color:#EEBD3A;'>").postTags("</span>"));
//            }
//            MatchQueryBuilder matchMessage = QueryBuilders.matchQuery("message", message);
//            if (matchOperator) {
//                matchMessage.operator(Operator.AND);
//            }
//            if (sortHitScoreDesc) bool.must(matchMessage);
//            else if (sortTimestampDesc) bool.filter(matchMessage);
//        }
//
//        // 排除的 message
//        if (StrUtil.isNotBlank(notMessage)) {
//            MatchQueryBuilder notMatchMessage = QueryBuilders.matchQuery("message", notMessage);
//            if (matchOperator) {
//                notMatchMessage.operator(Operator.AND);
//            }
//            bool.mustNot(notMatchMessage);
//        }
//
//        if (sortTimestampDesc) {
//            searchSource.sort("datetime", SortOrder.DESC);
//        }
//
//        if (debug) {
//            log.debug("日志收集查询条件: {}", bool.toString());
//        }
//
//        SearchResponse resp = esCurdManager.search(indexName, searchSource);
//
//        EsPageRes<EsPageVO> pageRes = new EsPageRes<>();
//        List<EsPageVO> pageData = new ArrayList<>();
//        pageRes.setDatas(pageData);
//        pageRes.setTook(resp.getTook().duration());
//
//        SearchHits hits = resp.getHits();
//        pageRes.setTotal(hits.getTotalHits().value);
//        pageRes.setPageSize(0);
//        pageRes.setPageNum(pageNum);
//        pageRes.setPageSize(pageSize);
//        pageRes.setTotalPage((int) (pageRes.getTotal() / pageSize));
//
//        for (SearchHit hit : hits) {
//            if (MapUtil.isNotEmpty(hit.getSourceAsMap())) {
//                EsPageVO data = new EsPageVO();
//                data.setIndex(hit.getIndex());
//                data.setId(hit.getId());
//                data.setScore(hit.getScore());
//                data.setDatetime((String) hit.getSourceAsMap().get("datetime"));
//
//                // 如果高亮则获取高亮字段
//                if (MapUtil.isNotEmpty(hit.getHighlightFields())) {
//                    data.setMessage(hit.getHighlightFields().get("message").getFragments()[0].toString());
//                } else {
//                    data.setMessage((String) hit.getSourceAsMap().get("message"));
//                }
//
//                data.setLevel((String) hit.getSourceAsMap().get("level"));
//                data.setThread((String) hit.getSourceAsMap().get("thread"));
//                data.setTraceId((String) hit.getSourceAsMap().get("traceId"));
//                data.setClazz((String) hit.getSourceAsMap().get("class"));
//                data.setIp((String) hit.getSourceAsMap().get("ip"));
//                data.setHostName((String) hit.getSourceAsMap().get("hostName"));
//                data.setAppName((String) hit.getSourceAsMap().get("appName"));
//                pageData.add(data);
//            }
//        }
//
//        return R.ok(pageRes);
//    }
//
//    /**
//     * 日志饼图
//     *
//     * @param indexName 索引名称, 当日志存放在不同索引时, 可以根据索引名称进一步缩小查询范围
//     * @param appName   应用名称
//     * @param debug     打印查询条件
//     * @return 饼图
//     */
//    @GetMapping("/log/chart/level/pie")
//    public R<List<LogLevelPieRes>> levelPie(@RequestParam String indexName,
//                                            @RequestParam(required = false) String appName,
//                                            @RequestParam(required = false) boolean debug) {
//        DateSection dateSection = getDateSection();
//
//        List<LogLevelPieRes> all = new ArrayList<>();
//        for (String level : levels) {
//            BoolQueryBuilder bool = new BoolQueryBuilder();
//
//
//            // 应用名称
//            if (StrUtil.isNotBlank(appName)) {
//                MatchQueryBuilder matchAppName = QueryBuilders.matchQuery("appName", appName);
//                bool.must(matchAppName);
//            }
//
//            bool.must(QueryBuilders
//                    .rangeQuery("datetime")
//                    .format("yyyy-MM-dd HH:mm:ss")
//                    .gte(dateSection.getBeginDT())
//                    .lte(dateSection.getEndDT())
//            )
//                    .must(QueryBuilders.matchQuery("level", level));
//
//            if (debug) {
//                log.debug("========== [{}]日志打印 =========", level);
//                log.debug("\n========== 查询条件========== \n{}", bool.toString());
//            }
//
//            long count = esCurdManager.count(indexName, bool);
//            String leveName = String.format("%s(%s)", level, count);
//            LogLevelPieRes levelPie = new LogLevelPieRes(level, leveName, count);
//
//            all.add(levelPie);
//        }
//
//        return R.ok(all);
//    }
//
//    /**
//     * 日志多轴折线图
//     *
//     * @param indexName 索引名称
//     * @param appName   应用名称
//     * @param debug     打印日志
//     * @return 折线图
//     */
//    @GetMapping("/log/chart/level/line")
//    public R<LogLevelLineRes> levelLine(
//            @RequestParam String indexName,
//            @RequestParam(required = false) String appName,
//            @RequestParam(required = false) boolean debug) {
//        DateSection dateSection = getDateSection();
//
//        LogLevelLineRes all = new LogLevelLineRes();
//
//        String[] logDatetime = null;
//
//        for (String level : levels) {
//            SearchSourceBuilder searchSource = new SearchSourceBuilder()
//                    .timeout(TimeValue.timeValueSeconds(5)).size(0).fetchSource(false);
//
//            BoolQueryBuilder bool = new BoolQueryBuilder();
//            bool.must(QueryBuilders
//                    .rangeQuery("datetime")
//                    .format("yyyy-MM-dd HH:mm:ss")
//                    .gte(dateSection.getBeginDT())
//                    .lte(dateSection.getEndDT())
//            )
//                    .must(QueryBuilders.matchQuery("level", level));
//
//            // 应用名称
//            if (StrUtil.isNotBlank(appName)) {
//                MatchQueryBuilder matchAppName = QueryBuilders.matchQuery("appName", appName);
//                bool.must(matchAppName);
//            }
//
//            AggregationBuilder aggs = AggregationBuilders
//                    .dateHistogram("日期直方图")
//                    .field("datetime")
//                    .format("yyyy-MM-dd HH:mm:ss")
//                    .fixedInterval(new DateHistogramInterval("30m"))
//                    .extendedBounds(new ExtendedBounds(dateSection.getBeginDT(), dateSection.getEndDT()));
//
//            if (debug) {
//                log.debug("========== [{}]日志打印 =========", level);
//                log.debug("\n========== 查询条件========== \n{}", bool.toString());
//                log.debug("\n========== 聚合条件========== \n{}", JSONUtil.formatJsonStr(aggs.toString()));
//            }
//
//            searchSource.query(bool).aggregation(aggs);
//
//            SearchResponse resp = esCurdManager.search(indexName, searchSource);
//            Aggregations aggregations = resp.getAggregations();
//            XzException400.throwBy(ObjUtil.isNull(aggregations), "未查询到日志折线图统计信息");
//
//            ParsedDateHistogram dateHistogram = aggregations.get("日期直方图");
//            List<? extends Histogram.Bucket> buckets = dateHistogram.getBuckets();
//
//            String[] log = new String[buckets.size()];
//
//            if (logDatetime == null) {
//                logDatetime = new String[buckets.size()];
//            }
//
//            for (int i = 0; i < buckets.size(); i++) {
//                Histogram.Bucket bucket = buckets.get(i);
//                logDatetime[i] = bucket.getKeyAsString();
//                log[i] = String.valueOf(bucket.getDocCount());
//            }
//
//            switch (level) {
//                case "DEBUG":
//                    all.setDebug(log);
//                    break;
//                case "INFO":
//                    all.setInfo(log);
//                    break;
//                case "WARN":
//                    all.setWarn(log);
//                    break;
//                case "ERROR":
//                    all.setError(log);
//                    break;
//            }
//            all.setDatetime(logDatetime);
//        }
//
//        return R.ok(all);
//    }
//
//    /**
//     * 查询索引原文
//     *
//     * @param index 索引
//     * @param id    文档ID
//     * @return 索引原文
//     */
//    @GetMapping("/log/source")
//    public R<?> source(String index, String id) {
//        return R.ok(esCurdManager.getSource(index, id));
//    }
//
//    private DateSection getDateSection() {
//        DateSection dateSection = new DateSection();
//        DateTime beginDate = DateUtil.date();
//        DateTime endDate = DateUtil.offsetDay(beginDate, -1);
//        String beginDT = DateUtil.format(beginDate, "yyyy-MM-dd HH:mm:ss");
//        String endDT = DateUtil.format(endDate, "yyyy-MM-dd HH:mm:ss");
//        dateSection.setEndDT(beginDT);
//        dateSection.setEndDate(beginDate);
//        dateSection.setBeginDT(endDT);
//        dateSection.setBeginDate(endDate);
//        return dateSection;
//    }
//
//    @Data
//    private static class DateSection {
//        private String beginDT;
//        private String endDT;
//
//        private Date beginDate;
//        private Date endDate;
//    }
//
//
//}
